package com.hangzhou.xyj.engine;

import android.content.Context;
import android.util.Log;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.hangzhou.xyj.XYJApplication;
import com.hangzhou.xyj.event.LocationRespEvent;
import com.hangzhou.xyj.event.TimeOutEvent;
import com.hangzhou.xyj.event.base.EventCode;
import com.hangzhou.xyj.event.base.ExceptionEvent;
import com.hangzhou.xyj.model.XXLocation;
import com.hangzhou.xyj.utils.EventBusUtil;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;

/**
 * Created by dfb on 2016/1/7.
 * 请求定位类
 */
public class BaiduMapLocationEngine implements EventCode {
    private static final String TAG = BaiduMapLocationEngine.class.getSimpleName();

    private static final int LOCATE_TIME_OUT = 10000;    //定位超时时间

    private LocationClient mLocationClient = null;
//    private LocationClientOption mLocationOption = null;

    private BDLocationListener mLocationListener;

    private XXLocation mLocation; //本类定位获取的一个Location

    private TimeOutHandler mTimeOutHandler;

    private Object mEventTag;   //事件tag,将事件发送给请求者

    private boolean isLocationSuccessFinish = false;    //定位逻辑是否完成标识
    private boolean isAreaCodeFinish = false;   // 转换地区编码是否完成

    private boolean mIsTestInVersion; //是否是testIN的版本
    private Context mContext;

    public BaiduMapLocationEngine() {
        init();
    }

    public BaiduMapLocationEngine(Object eventTag) {
        setEventTag(eventTag);
        init();
    }

    public void setEventTag(Object eventTag) {
        this.mEventTag = eventTag;
    }

    /**
     * 初始化必要信息
     */
    private void init() {
        mTimeOutHandler = new TimeOutHandler(TAG);
        mTimeOutHandler.setTimeOut(LOCATE_TIME_OUT);
        mContext = XYJApplication.mAppContext;
    }

    /**
     * 停止定位，资源释放
     *
     * @param
     * @return
     * @author yaohuix
     * @date 2016/3/30 14:14
     */
    private void stopLocation() {
        if (mLocationClient != null) {
            mLocationClient.stop();
            mLocationClient = null;
//            mLocationOption = null;
        }
    }

    /**
     * 请求定位后续步骤
     * 1.根据配置信息决定使用哪个定位系统
     * 同步该方法，防止多线程定位事件紊乱
     */
    public void requestLocation() {
        //没有设置事件tag，抛异常，调用者处理
        if (mEventTag == null) {
            throw new IllegalArgumentException("req location event tag cannot be null");
        }

        //注册该对象到EventBut的接收队列中
        EventBusUtil.register(this);

        //请求定位前，置2个任务都未完成
        isLocationSuccessFinish = false;    //定位逻辑是否完成标识
        isAreaCodeFinish = false;   // 转换地区编码是否完成

        //请求定位前：开启超时任务
        mTimeOutHandler.start();

        //NOTE(dfb): 根据配置来决定使用哪个定位:定位前停止定位，防止重复点击定位
        stopLocation();
        //发送开始请求定位事件
        EventBusUtil.postEvent(new LocationRespEvent(EventCode.START).setTag(mEventTag));

        baiduRequestLocation();
    }

    /**
     * 百度请求定位
     */
    private void baiduRequestLocation() {
        Log.d(TAG, "requestNewLocation: baidumap");
        LocationClientOption mLocationOption = new LocationClientOption();
        if (mLocationClient == null) {
            mLocationClient = new LocationClient(mContext);

        }
//        if (mLocationOption == null) {
//            mLocationOption = new LocationClientOption();
//        }
        if (mLocationListener == null) {
            mLocationListener = new MyBDLocationListener();
        }


        mLocationOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy
        );//可选，默认高精度，设置定位模式，高精度，低功耗，仅设备
        mLocationOption.setCoorType("bd09ll");//可选，默认gcj02，设置返回的定位结果坐标系
        int span = 1000;
        mLocationOption.setScanSpan(span);//可选，默认0，即仅定位一次，设置发起定位请求的间隔需要大于等于1000ms才是有效的
        mLocationOption.setIsNeedAddress(true);//可选，设置是否需要地址信息，默认不需要
        mLocationOption.setAddrType("all");
        mLocationOption.setOpenGps(true);//可选，默认false,设置是否使用gps
        mLocationOption.setLocationNotify(true);//可选，默认false，设置是否当gps有效时按照1S1次频率输出GPS结果
//        mLocationOption.setIsNeedLocationDescribe(true);//可选，默认false，设置是否需要位置语义化结果，可以在BDLocation.getLocationDescribe里得到，结果类似于“在北京天安门附近”
//        mLocationOption.setIsNeedLocationPoiList(true);//可选，默认false，设置是否需要POI结果，可以在BDLocation.getPoiList里得到
        mLocationOption.setIgnoreKillProcess(false);//可选，默认true，定位SDK内部是一个SERVICE，并放到了独立进程，设置是否在stop的时候杀死这个进程，默认不杀死
        mLocationOption.SetIgnoreCacheException(false);//可选，默认false，设置是否收集CRASH信息，默认收集
        mLocationOption.setEnableSimulateGps(false);//可选，默认false，设置是否需要过滤gps仿真结果，默认需要
        mLocationClient.setLocOption(mLocationOption);
        /**
         * 配置定位参数
         */
        // 设置定位模式为高精度定位模式
//        mLocationOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
//        //设置是否返回地址信息（默认返回地址信息）
//        mLocationOption.setIsNeedAddress(true);
//        //设置坐标类型
//        mLocationOption.setCoorType("bd09ll");
//        //设置是否打开gps进行定位
//        mLocationOption.setOpenGps(true);
        //设置是否只定位一次,默认为false
//        mLocationOption.setOnceLocation(true);
        //设置是否强制刷新WIFI，默认为强制刷新
//        mLocationOption.setWifiActiveScan(true);
        //设置是否允许模拟位置,默认为false，不允许模拟位置
//        mLocationOption.setMockEnable(false);
        //设置定位间隔,单位毫秒,默认为2000ms:单次定位不设置
//        mLocationOption.setInterval(2000);
//        // 设置定位参数
//        mLocationClient.setLocOption(mLocationOption);
        // 设置定位监听
        mLocationClient.registerLocationListener(mLocationListener);
        // 启动定位
        mLocationClient.start();
    }

    /**
     * 定位成功：发送定位成功事件
     */
    private void reqLocationSuccess() {
        Log.d(TAG, "get req location success");
        //取消超时机制
        mTimeOutHandler.cancel();
        LocationRespEvent event = new LocationRespEvent(EventCode.SUCCESS, mLocation);
        event.setTag(mEventTag);
        EventBusUtil.postEvent(event);

        //注销本类的EventBus
        EventBusUtil.unregister(this);
        stopLocation();
    }

    /**
     * 定位失败
     */
    public void reqLocationFail(int errCode, String errMsg) {
        Log.e(TAG, "request location fail: " + errMsg + "   errCode: " + errCode);
        //取消超时机制
        mTimeOutHandler.cancel();
        stopLocation();
        EventBus.getDefault().post(new LocationRespEvent(FAIL, new ExceptionEvent(errCode, errMsg)).setTag(mEventTag));

        //注销本类的EventBus
        EventBusUtil.unregister(this);
    }

    /**
     * 超时消息处理
     */
    @Subscribe
    public void onEventMainThread(TimeOutEvent event) {
        //只处理本类消息
        if (!TAG.equals(event.getTag())) {
            return;
        }

        switch (event.getCode()) {
            case START:
                Log.d(TAG, "timeout handler start...");
                break;
            case SUCCESS:
                Log.d(TAG, "request location timeout...");
                String timeoutMsg = "";
                int errCode = 0;

                //定位系统超时，校验哪个任务没完成,发送定位失败事件
                if (!isLocationSuccessFinish) { //地图定位未完成
                    timeoutMsg = "Baidu request location timeout";
                    reqLocationFail(errCode, timeoutMsg);
                    return;
                }

                if (!isAreaCodeFinish) {//转换地区编码未完成
                    timeoutMsg = "get areaCode timeout";
                    errCode = 0;
                    reqLocationFail(errCode, timeoutMsg);
                }
                break;
        }
    }

    /**
     * 百度地图监听回调
     */
    private class MyBDLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation bdLocation) {
            if (bdLocation == null) {
                reqLocationFail(0, "BaiduMap request location fail ,BDLocation is null");
                return;
            }
            //正确返回
            mLocation = new XXLocation(bdLocation.getLatitude(), bdLocation.getLongitude(), bdLocation.getAddrStr());
            mLocation.province = bdLocation.getProvince();
            mLocation.city = bdLocation.getCity();
            mLocation.district = bdLocation.getDistrict();
            mLocation.detail = bdLocation.getAddrStr();
            mLocation.originCityCode = bdLocation.getCityCode(); //地区编码
            //如果定位过程超时了，则不需要转换地区编码,超时机制已经处理了定位失败
            if (mTimeOutHandler.isTimeOut()) {
                Log.e(TAG, "BaiduMap request location success" + mLocation.getDetailAddress() + ", but handler is timeout");
                return;
            }
            //地区编码获取成功：正在定位成功
            reqLocationSuccess();
        }
    }
}
